package org.jeecg.modules.wechatwork.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jeecg.modules.wechatwork.config.WechatWorkProperties;
import org.jeecg.modules.wechatwork.model.DomainVerificationResult;
import org.jeecg.modules.wechatwork.model.VerificationFile;
import org.jeecg.modules.wechatwork.model.WechatServerIPs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * WeChat Work 域名验证服务类
 * 
 * @author Your Name
 * @version 1.0.0
 */
@Slf4j
@Service
public class WechatWorkDomainVerificationService {

    @Autowired
    private WechatWorkProperties properties;

    private final HttpClient httpClient = HttpClients.createDefault();

    /**
     * 验证回调 URL 签名
     * 
     * @param signature 签名
     * @param timestamp 时间戳
     * @param nonce 随机数
     * @param echostr 随机字符串
     * @return 验证成功返回 echostr，失败返回 null
     */
    public String verifyCallbackURL(String signature, String timestamp, String nonce, String echostr) {
        try {
            // 验证必需参数
            if (signature == null || timestamp == null || nonce == null || echostr == null) {
                log.error("缺少必需参数: signature={}, timestamp={}, nonce={}, echostr={}", 
                         signature, timestamp, nonce, echostr);
                return null;
            }
            // 按字典序排序参数
            String[] params = {properties.getToken(), timestamp, nonce};
            Arrays.sort(params);

            // 拼接字符串
            String concatenatedString = String.join("", params);

            // 计算 SHA1 签名
            String calculatedSignature = DigestUtils.sha1Hex(concatenatedString);

            // 比较签名
            if (calculatedSignature.equals(signature)) {
                log.info("回调 URL 验证成功");
                return echostr;
            } else {
                log.error("签名验证失败: 期望={}, 实际={}", calculatedSignature, signature);
                return null;
            }
        } catch (Exception e) {
            log.error("验证回调 URL 时发生错误", e);
            return null;
        }
    }

    /**
     * 验证消息签名（用于加密消息）
     * 
     * @param msgSignature 消息签名
     * @param timestamp 时间戳
     * @param nonce 随机数
     * @param body 请求体
     * @return 验证是否成功
     */
    public boolean verifyMessageSignature(String msgSignature, String timestamp, String nonce, String body) {
        try {
            // 验证必需参数
            if (msgSignature == null || timestamp == null || nonce == null || body == null) {
                log.error("缺少必需参数: msgSignature={}, timestamp={}, nonce={}, body={}", 
                         msgSignature, timestamp, nonce, body);
                return false;
            }

            // 解析加密消息
            String encryptedMessage = parseEncryptedMessage(body);
            if (encryptedMessage == null) {
                log.error("无法解析加密消息");
                return false;
            }

            // 按字典序排序参数
            String[] params = {properties.getToken(), timestamp, nonce, encryptedMessage};
            Arrays.sort(params);

            // 拼接字符串
            String concatenatedString = String.join("", params);

            // 计算 SHA1 签名
            String calculatedSignature = DigestUtils.sha1Hex(concatenatedString);

            // 比较签名
            if (calculatedSignature.equals(msgSignature)) {
                log.info("消息签名验证成功");
                return true;
            } else {
                log.error("消息签名验证失败: 期望={}, 实际={}", calculatedSignature, msgSignature);
                return false;
            }
        } catch (Exception e) {
            log.error("验证消息签名时发生错误", e);
            return false;
        }
    }

    /**
     * 解析加密消息
     * 
     * @param body 请求体
     * @return 加密消息内容
     */
    private String parseEncryptedMessage(String body) {
        try {
            Pattern pattern = Pattern.compile("<Encrypt><!\\[CDATA\\[(.*?)\\]\\]></Encrypt>");
            Matcher matcher = pattern.matcher(body);
            if (matcher.find()) {
                return matcher.group(1);
            }
            return null;
        } catch (Exception e) {
            log.error("解析加密消息时发生错误", e);
            return null;
        }
    }

    /**
     * 获取业务域名验证文件
     * 
     * @param accessToken 访问令牌
     * @return 验证文件信息
     */
    public VerificationFile getBusinessDomainVerificationFile(String accessToken) throws IOException {
        String url = "https://api.weixin.qq.com/wxa/get_webviewdomain_confirmfile?access_token=" + accessToken;
        
        HttpPost post = new HttpPost(url);
        post.setHeader("Content-Type", "application/json");
        post.setEntity(new StringEntity("{}"));

        HttpResponse response = httpClient.execute(post);
        String responseBody = EntityUtils.toString(response.getEntity());

        log.info("获取验证文件响应: {}", responseBody);

        // 这里需要根据实际响应格式解析 JSON
        // 简化处理，实际项目中应该使用 Jackson 解析
        if (responseBody.contains("\"errcode\":0")) {
            // 解析成功响应
            return new VerificationFile();
        } else {
            throw new IOException("获取验证文件失败: " + responseBody);
        }
    }

    /**
     * 验证域名可访问性
     * 
     * @param domainUrl 域名 URL
     * @param expectedContent 期望内容
     * @return 验证结果
     */
    public DomainVerificationResult verifyDomainAccessibility(String domainUrl, String expectedContent) {
        try {
            URL url = new URL(domainUrl);
            HttpGet get = new HttpGet(domainUrl);
            get.setHeader("User-Agent", "WeChatWork-DomainVerification/1.0.0");

            HttpResponse response = httpClient.execute(get);
            String content = EntityUtils.toString(response.getEntity());

            DomainVerificationResult result = new DomainVerificationResult();
            result.setUrl(domainUrl);
            result.setSuccess(response.getStatusLine().getStatusCode() == 200);
            result.setStatusCode(response.getStatusLine().getStatusCode());
            result.setContent(content);

            if (expectedContent != null) {
                result.setContentMatch(content.contains(expectedContent));
            }

            return result;
        } catch (Exception e) {
            log.error("验证域名可访问性时发生错误: {}", domainUrl, e);
            DomainVerificationResult result = new DomainVerificationResult();
            result.setUrl(domainUrl);
            result.setSuccess(false);
            result.setError(e.getMessage());
            return result;
        }
    }

    /**
     * 获取 WeChat 服务器 IP 列表
     * 
     * @param accessToken 访问令牌
     * @return IP 列表
     */
    public WechatServerIPs getWechatServerIPs(String accessToken) throws IOException {
        String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=" + accessToken;
        
        HttpGet get = new HttpGet(url);
        HttpResponse response = httpClient.execute(get);
        String responseBody = EntityUtils.toString(response.getEntity());

        log.info("获取 WeChat 服务器 IP 响应: {}", responseBody);

        // 这里需要根据实际响应格式解析 JSON
        // 简化处理，实际项目中应该使用 Jackson 解析
        if (responseBody.contains("\"errcode\":0")) {
            // 解析成功响应
            return new WechatServerIPs();
        } else {
            throw new IOException("获取 WeChat 服务器 IP 失败: " + responseBody);
        }
    }

    /**
     * 验证域名格式
     * 
     * @param domain 域名
     * @return 是否有效
     */
    public boolean validateDomainFormat(String domain) {
        try {
            URL url = new URL(domain);
            String protocol = url.getProtocol();
            return "http".equals(protocol) || "https".equals(protocol);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 生成验证响应
     * 
     * @param success 是否成功
     * @param message 消息
     * @return 响应内容
     */
    public String generateVerificationResponse(boolean success, String message) {
        if (success) {
            return "success";
        } else {
            return message != null ? message : "verification failed";
        }
    }
} 